#include <Arduino.h>
#include "RFIDNFCLib.h"
#include "HardwareSerial.h"

bool RFIDNFCLib::StartRFIDNFC(void){
	#ifdef DEBUG_RFIDNFC
		Serial.print("\tStarted RFID/NFC: { ");
	#endif
	// Just to start syncronization
	Serial1.print("                ");
    
	memset(dataTX, 0x00, 35);
	dataTX[0] = 0x02; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4; // CODE
	dataTX[3] = 0x02; //TFI
	checkSum(dataTX); //0x2A; //Checksum 
	#ifdef DEBUG_RFIDNFC
		Serial.print("Firmware : ");
	#endif
	sendTX(dataTX , 5 , 17, false);
	

	for (int i = 11; i < (15) ; i++){
		#ifdef DEBUG_RFIDNFC
			Serial.print(dataRX[i], HEX);
			Serial.print(" ");
		#endif
	}

	#ifdef DEBUG_RFIDNFC
		Serial.println(" }");
	#endif
}

bool RFIDNFCLib::ConfigureSAM(void){
	Serial1.print("               ");

	dataTX[0] = 0x05; //Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x14;
	dataTX[4] = 0x01; // Normal mode
	dataTX[5] = 0x14; // TimeOUT
	dataTX[6] = 0x00; // IRQ
	dataTX[7] = 0x00; // Clean checkSum position
	checkSum(dataTX);

	while (!sendTX(dataTX , 8, 13, false)){
	}
	#ifdef DEBUG_RFIDNFC
		Serial.println("\tConfigured SAM");
	#endif
}

bool RFIDNFCLib::Diagnose(void){
	dataTX[0] = 0x04; //Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x00;
	dataTX[4] = 0x00; // NumTst
	dataTX[5] = 0xA0; // [InParam]
	dataTX[5] = 0xB0; // [InParam]
	checkSum(dataTX);

	sendTX(dataTX , 8, 13, false);

	if (dataRX[0] == 0x00)
		return true;
	else
		return false;
}

//!The goal of this command is to detect as many targets (maximum MaxTg)
// as possible in passive mode.
uint8_t RFIDNFCLib::DetectTag(void){
	Serial1.flush();

	dataTX[0] = 0x04; // Length
	lengthCheckSum(dataTX); // Length Checksum
	dataTX[2] = 0xD4;
	dataTX[3] = 0x4A; // Code
	dataTX[4] = 0x01; //MaxTarget
	dataTX[5] = 0x00; //BaudRate = 106Kbps
	dataTX[6] = 0x00; // Clear checkSum position
	checkSum(dataTX); 

	sendTX(dataTX , 7 ,23, true);

	for (int i = 17; i < (21) ; i++){
		_UID[i-17] = dataRX[i];
	}

	ATQ[0] = dataRX[13];
	ATQ[1] = dataRX[14];

	if ((dataRX[9]== 0xD5) & (dataRX[10] == 0x4B) & (dataRX[11] == 0x01)) {
		return 0;
	} else {
		return 1;
	}
}

void RFIDNFCLib::PrintUIDTagDetected(void){
	#ifdef DEBUG_RFIDNFC
		Serial.print("\tPrint UID Tag Detected: { ");
		Serial.print("UID : ");
		for (int i = 0; i < (4) ; i ++){
			Serial.print(_UID[i], HEX);
			Serial.print(" ");
		}
		Serial.println(" }");
	#endif
}

bool RFIDNFCLib::sendTX(uint8_t *_dataTX, uint8_t length, uint8_t outLength, bool _wait){
	Serial1.write((byte)0x00);
	Serial1.write((byte)0x00);
	Serial1.write((byte)0xFF); 

	for (int i = 0; i < length; i++) {
		Serial1.write((byte)_dataTX[i]);
	}

	Serial1.write((byte)0x00);
	Serial1.flush();
	if (!getACK(_wait))
		return false;
	if (!waitResponse(_wait))// Receive response.
		return false;
	getData(outLength);

	return true;
}

//!Wait for ACK response and stores it in the dataRX buffer
bool RFIDNFCLib::getACK(bool _wait){
	delay(5);
	if (!waitResponse(_wait))
		return false;
	for (int i = 0; i < 5 ; i++) {
		dataRX[i] = Serial1.read();
	}
	return true;
}
//**********************************************************************
//!Wait the response of the module
bool RFIDNFCLib::waitResponse(bool _wait){
	int val = 0xFF;
	int cont = 0x00;

	while(val != 0x00) { //Wait for 0x00 response
		val = Serial1.read();
		delay(5);
		cont ++;
		if (cont > 0x20)
			if (!_wait)
				return false;
	}
	return true;
}

void RFIDNFCLib::getData(uint8_t outLength){
	for (int i=5; i < outLength; i++) {
		dataRX[i] = Serial1.read();//read data from the module.
	}
}

void RFIDNFCLib::checkSum(uint8_t *_dataTX){
	for (int i = 0; i < _dataTX[0] ; i++){
		_dataTX[_dataTX[0] + 2] += _dataTX[i + 2];
	}
	byte(_dataTX[_dataTX[0] + 2]= - _dataTX[_dataTX[0] + 2]);
}
//**********************************************************************
//!Calculates the length checksum and sotres it in the buffer.
uint8_t RFIDNFCLib::lengthCheckSum(uint8_t *_dataTX){
	_dataTX[1] = byte(0x100 - _dataTX[0]);
}



